import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageEnhance, ImageStat
from skimage import feature, exposure
from scipy.ndimage import gaussian_filter


def adjust_intensity(gray, threshold=160, intensity=40,
                     mode='lower', action='lighten',
                     contrast_factor=1.0):
    """
    对灰度图中高于或低于阈值的区域进行亮度调整（增亮或调暗）

    参数:
    gray: 输入的灰度图像（单通道）
    threshold: 阈值 (0-255)
    intensity: 调整强度 (0-255)
    mode: 选择区域 - 'higher'(高于阈值) 或 'lower'(低于阈值)
    action: 调整动作 - 'lighten'(增亮) 或 'darken'(调暗)
    contrast_factor: 对比度增强因子 (大于1的值)

    返回:
    original: 原始图像
    adjusted: 调整后的图像
    mask: 调整区域的掩模
    """
    # 创建原始图像的副本
    adjusted = gray.copy().astype(np.float32)

    # 创建阈值掩模
    if mode == 'higher':
        mask = gray > threshold
    elif mode == 'lower':
        mask = gray < threshold
    else:
        raise ValueError("mode 应为 'higher' 或 'lower'")

    # 根据动作类型调整强度方向
    if action == 'darken':
        intensity = -intensity

    # 应用亮度调整
    adjusted[mask] = adjusted[mask] + intensity

    # 应用对比度增强（如果启用）
    if contrast_factor != 1.0:
        # 公式: output = contrast_factor*(input - 128) + 128
        adjusted[mask] = contrast_factor * (adjusted[mask] - 128) + 128

    # 确保像素值在0-255范围内
    adjusted = np.clip(adjusted, 0, 255).astype(np.uint8)

    return gray, adjusted, mask


def adaptive_contrast_enhancement(image, base_intensity=30, contrast_factor=1.5,
                                  min_region_size=5, max_region_size=20,
                                  sigma=3.0, clip_limit=2.0, tile_size=8):
    """
    基于局部明暗差自适应增强对比度的函数

    参数:
    image: 输入图像 (灰度或彩色)
    base_intensity: 基础增强强度 (0-100)
    contrast_factor: 对比度增强因子 (1.0-3.0)
    min_region_size: 最小局部区域尺寸 (像素)
    max_region_size: 最大局部区域尺寸 (像素)
    sigma: 高斯模糊参数 (用于计算局部差异)
    clip_limit: CLAHE的裁剪限制 (2.0-4.0)
    tile_size: CLAHE的网格大小 (像素)

    返回:
    增强后的图像
    """
    # 转换为浮点类型以进行精确计算
    img = image.astype(np.float32) / 255.0

    # 如果是彩色图像，转换为HSV空间处理V通道
    if len(image.shape) == 3:
        hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
        v_channel = hsv[:, :, 2].astype(np.float32) / 255.0
    else:
        v_channel = img.copy()

    # 计算局部明暗差异
    # 使用高斯模糊来模拟局部区域
    blurred = gaussian_filter(v_channel, sigma=sigma)
    local_diff = np.abs(v_channel - blurred)

    # 归一化局部差异 (0-1)
    min_diff = np.min(local_diff)
    max_diff = np.max(local_diff)
    if max_diff > min_diff:
        normalized_diff = (local_diff - min_diff) / (max_diff - min_diff)
    else:
        normalized_diff = np.zeros_like(local_diff)

    # 计算自适应强度图 (差异越小，强度越大)
    # 使用指数函数使调整更平滑
    adaptive_map = np.exp(-5.0 * normalized_diff)

    # 计算最终增强强度图
    intensity_map = base_intensity / 100.0 * adaptive_map

    # 应用亮度调整
    enhanced_v = v_channel.copy()

    # 增强暗区
    dark_mask = v_channel < 0.5
    enhanced_v[dark_mask] = enhanced_v[dark_mask] * (1.0 + intensity_map[dark_mask])

    # 减弱亮区
    light_mask = v_channel >= 0.5
    enhanced_v[light_mask] = enhanced_v[light_mask] * (1.0 - intensity_map[light_mask] * 0.5)

    # 应用对比度增强
    mean_value = np.mean(enhanced_v)
    enhanced_v = (enhanced_v - mean_value) * contrast_factor + mean_value

    # 限制在0-1范围内
    enhanced_v = np.clip(enhanced_v, 0, 1)

    # 应用CLAHE进行局部对比度增强
    clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=(tile_size, tile_size))
    enhanced_v_8bit = (enhanced_v * 255).astype(np.uint8)
    enhanced_v_clahe = clahe.apply(enhanced_v_8bit).astype(np.float32) / 255.0

    # 融合原始增强和CLAHE结果
    final_v = 0.7 * enhanced_v + 0.3 * enhanced_v_clahe

    # 如果是彩色图像，合并回HSV空间
    if len(image.shape) == 3:
        hsv[:, :, 2] = final_v * 255
        result = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
    else:
        result = final_v * 255

    # 转换为8位图像
    return result.astype(np.uint8)


def enhance_contrast_auto(gray,
                          clip_limit=2.0,
                          tile=8,
                          method='clahe'):
    """
    根据图像自身明暗差自适应增强对比度。
    返回 uint8 单通道图。

    参数
    ----
    gray       : 2-D uint8 灰度图
    clip_limit : CLAHE 剪切系数
    tile       : CLAHE 分块大小
    method     : 'clahe' | 'gamma'
    """
    if gray.ndim != 2:
        raise ValueError('输入必须是 2-D 灰度图')
    if gray.dtype != np.uint8:
        gray = gray.astype(np.uint8)

    gmin, gmax = gray.min(), gray.max()
    diff = gmax - gmin

    if diff == 0:  # 全图单色
        return gray

    # ---- 1. 计算强度因子：差越小，alpha 越大 ----
    alpha = 255.0 / diff  # 线性拉伸系数
    alpha = np.clip(alpha, 1.5, 5.0)  # 限制最大放大倍数

    # ---- 2. 方法 A：CLAHE（推荐） ----
    if method == 'clahe':
        clahe = cv2.createCLAHE(clipLimit=clip_limit * (alpha / 5.0),
                                tileGridSize=(tile, tile))
        return clahe.apply(gray)

    # ---- 3. 方法 B：幂律 (gamma) 变换 ----
    elif method == 'gamma':
        # gamma < 1 提亮暗部，gamma > 1 压暗亮部
        # 这里把 gamma 与 alpha 反相关
        gamma = 1.0 / (alpha * 0.5)
        inv_gamma = 1.0 / gamma
        table = np.array([((i / 255.0) ** inv_gamma) * 255
                          for i in np.arange(256)]).astype(np.uint8)
        return cv2.LUT(gray, table)

    else:
        raise ValueError('method 必须是 clahe 或 gamma')


import cv2
import numpy as np


def adaptive_contrast_adjustment(image, target_std=64, max_alpha=2.0, min_alpha=0.5):
    """
    自适应调整图像对比度
    参数:
        image: 输入图像(BGR或灰度)
        target_std: 目标标准差(推荐值40-80)
        max_alpha: 最大对比度增强系数
        min_alpha: 最小对比度减弱系数

    返回:
        调整后的图像
    """
    # 转换为浮点数以便精确计算
    working_img = image.astype(np.float32) / 255.0

    # 彩色图像处理
    if len(image.shape) == 3:
        # 转换为HSV空间并分离通道
        hsv = cv2.cvtColor(working_img, cv2.COLOR_BGR2HSV)
        v_channel = hsv[:, :, 2].copy()

        # 计算亮度的均值和标准差
        mean_val = np.mean(v_channel)
        std_val = np.std(v_channel)

        # 计算自适应调整系数
        if std_val < 1e-6:  # 避免除零错误
            alpha = max_alpha
        else:
            alpha = target_std / (std_val * 255)  # 缩放标准差到0-1范围
            alpha = max(min_alpha, min(alpha, max_alpha))  # 限制调整范围

        # 应用对比度调整
        v_channel = (v_channel - mean_val) * alpha + mean_val

        # 合并通道并转换回BGR
        hsv[:, :, 2] = np.clip(v_channel, 0, 1)
        result = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

    # 灰度图像处理
    else:
        # 计算均值和标准差
        mean_val = np.mean(working_img)
        std_val = np.std(working_img)

        # 计算自适应调整系数
        if std_val < 1e-6:
            alpha = max_alpha
        else:
            alpha = target_std / (std_val * 255)
            alpha = max(min_alpha, min(alpha, max_alpha))

        # 应用对比度调整
        result = (working_img - mean_val) * alpha + mean_val
        result = np.clip(result, 0, 1)

    # 转换回0-255整数范围
    return (result * 255).astype(np.uint8)

def image_preprocessing(img):
    """图片预处理"""
    # gray, enhanced, below_threshold_mask = adjust_intensity(img, threshold=170, mode='higher', action='lighten')
    # gray, enhanced, below_threshold_mask = adjust_intensity(enhanced, threshold=30, mode='lower', action='darken')



    enhanced = adaptive_contrast_adjustment(img)
    enhanced = exposure.rescale_intensity(img)
    print(np.std(img), ' > ', np.std(enhanced))

    plt.figure(figsize=(12, 8))
    plt.subplot(221), plt.imshow(img, cmap='gray'), plt.title('原图')
    plt.subplot(222), plt.imshow(enhanced, cmap='gray'), plt.title('对比度增强')
    plt.tight_layout()
    plt.show()

    return img, enhanced


if __name__ == '__main__':
    img_path = '../img/new/0012.tif'
    img = cv2.imread(img_path, 0)
    if img is None:
        print(f"错误:无法加载图像，请检查路径:{img_path}")
        exit()
    image_preprocessing(img)
